<?php
namespace Http;

use Helper\Logger;
use Net\Connection;

require_once "Net/Connection.php";
require_once dirname(__DIR__) . "/Helper/Logger.php";

class HttpConnection extends Connection {
    // protected $_proxyConnected = false;
    protected $_methodselect = false;
    protected $_forwardTo=null;
    protected $_forwardSize=0;
    
    const HTTP_VER_11 = 'HTTP/1.1';
    const HTTP_VER_10 = 'HTTP/1.0';
    
    const STATUS_REQUEST_TIMEOUT = 408;
    const STATUS_SUCCESS = 200;
    
    /**
     * 解析http协议
     * @param $content
     * @return array
     */
    static public function parseRequest($content) {
        $delimiterPos = strpos($content, "\r\n\r\n");
        $head = $content;
        $body = '';
        
        if($delimiterPos !== false) {
            $head = substr($content, 0, $delimiterPos);
            $body = substr($content, $delimiterPos+4);
        }
        
        $headInfo = [
            'body' => $body
        ];
        
        $headAry = array_filter(array_map('trim', explode("\r\n", $head)));
        $methodlLine = array_shift($headAry);
        $methodAry = array_filter(array_map('trim', explode(' ', $methodlLine)));
        
        $headInfo['method'] = strtoupper($methodAry[0]);
        $headInfo['request_path'] = $methodAry[1];
        $headInfo['http_version'] = $methodAry[2];
        $params = [];
        $paramsRaw = [];
        
        $paramsAry = array_map(function($row) {
            return array_filter(array_map('trim', explode(":", $row, 2)));
        }, $headAry);
        
        foreach ($paramsAry as $param) {
            $params[strtolower($param[0])] = strtolower($param[1]);
            $paramsRaw[$param[0]] = $param[1];
        }
        
        $headInfo['head_params'] = $params;
        $headInfo['head_params_raw'] = $paramsRaw;
        return $headInfo;
    }
    
    /**
     * 构建请求
     * @param $info
     * @return string
     */
    static public function buildRequest($info) {
        $content = "{$info['method']} {$info['request_path']} {$info['http_version']}\r\n";
        $content .= self::_buildHeadParams($info['head_params']);
    
        $content .= "\r\n\r\n";
        $content .= $info['body'];
        return $content;
    }
    
    static protected function _buildHeadParams($headParams) {
        return implode("\r\n",
            array_map(
                function($key, $value) {
                    return "$key: $value";
                },
                array_keys($headParams),
                array_values($headParams)
            )
        );
    }
    
    static public function parseUrl($url) {
        return parse_url($url);
    }
    
    static public function unparseUrl($parsedUrlData) {
        $scheme   = isset($parsedUrlData['scheme']) ? $parsedUrlData['scheme'] . '://' : '';
        $host     = isset($parsedUrlData['host']) ? $parsedUrlData['host'] : '';
        $port     = isset($parsedUrlData['port']) ? ':' . $parsedUrlData['port'] : '';
        $user     = isset($parsedUrlData['user']) ? $parsedUrlData['user'] : '';
        $pass     = isset($parsedUrlData['pass']) ? ':' . $parsedUrlData['pass']  : '';
        $pass     = ($user || $pass) ? "$pass@" : '';
        $path     = isset($parsedUrlData['path']) ? $parsedUrlData['path'] : '';
        $query    = isset($parsedUrlData['query']) ? '?' . $parsedUrlData['query'] : '';
        $fragment = isset($parsedUrlData['fragment']) ? '#' . $parsedUrlData['fragment'] : '';
        return "$scheme$user$pass$host$port$path$query$fragment";
    }
    
    public function setupTwoWayForwarding(HttpConnection $connection) {
        $this->setForwardTo($connection);
        $connection->setForwardTo($this);
        return ;
    }
    
    public function setForwardTo($connection) {
        if($connection === $this) {
            return $this;
        }
        
        $this->_forwardTo = $connection;
        return $this;
    }
    
    public function getForwardSize() {
        return $this->_forwardSize;
    }
    
    static function buildResponse($info, $statusCode=self::STATUS_SUCCESS, $statusMsg='OK', $version=self::HTTP_VER_11) {
        $info['head_params']['content-length'] = strlen($info['body']);
        $content = "$version $statusCode $statusMsg\r\n";
        $content .= self::_buildHeadParams($info['head_params']);
        $content .= "\r\n\r\n";
        $content .= $info['body'];
        return $content;
    }
    
    public function forward($msg) {
        if($this->getForwardTo()) {
            $len = strlen($msg);
            $log = "{$this} ===($len)===> {$this->getForwardTo()}";
            Logger::record("<--> $log", false);
            Logger::recordForwardContent($log, $msg);
            $this->_forwardSize += $len;
            $this->getForwardTo()->send($msg);
        }
        
        return $this;
    }
    
    /**
     * @return static|null
     */
    public function getForwardTo() {
        return $this->_forwardTo;
    }
    
    
    public function getForwardSizeHumanReadable() {
        $size = $this->getForwardSize();
        $gb = round($size / (1024*1024*1024), 2);
        $mb = round($size / (1024*1024), 2);
        $kb = round($size / 1024, 2);
        $b = $size;
        
        return array_values(array_filter([
            $gb>1?"{$gb}GB":'',
            $mb>1?"{$mb}MB":'',
            $kb>1?"{$kb}KB":'',
            "{$b}B",
        ]))[0];
    }
    
}